<template>
  <el-container>
    <el-header style="border-bottom: 1px solid #e6e6e6;"></el-header>
    <el-main class="none-padding">
      <!-- 添加 @click 事件处理函数 -->
      <el-table :data="tableData" 
        border stripe 
        size="small"
        style="width: 100%" 
        height="100%"
        @click="handleTableClick"
        @keydown="handleKeyDown"
        >
        <el-table-column prop="date" label="Date" width="180">
          <template #default="scope">
            <div>{{ scope.row.date }}</div>
          </template>
        </el-table-column>
        <el-table-column prop="name" label="Name">
          <template #default="scope">
            <el-select
              v-model="scope.row.name"
              filterable
              default-first-option
              automatic-dropdown
              placeholder="Select"
              size="small"
              :show-arrow="false"
              :offset="0"
              ref="editItem"
              @change="handleSelectChange"
              @visible-change="handleVisibleChange"
              @blur="handleInputBlur"
              v-if="editCoordProp === scope.$index + '_' + scope.column.property"
            >
              <el-option
                v-for="item in options"
                :key="item.value"
                :label="item.label"
                :value="item.value"
              />
            </el-select>
            <div v-else>{{ scope.row.name }}</div>
          </template>
        </el-table-column>
        <el-table-column prop="address" label="Address">
          <template #default="scope">
            <el-input 
              size="small" 
              v-model="scope.row.address" 
              placeholder="Please input"
              ref="editItem"
              @blur="handleInputBlur"
              v-if="editCoordProp === scope.$index + '_' + scope.column.property"
            />
            <div v-else>{{ scope.row.address }}</div>
          </template>
        </el-table-column>
      </el-table>
    </el-main>
    <el-footer style="border-top: 1px solid #e6e6e6;"></el-footer>
  </el-container>
</template>

<script setup>
import tableData from '@/mock/list.js'
import { onMounted, ref, reactive, nextTick } from 'vue'
// import * as _ from 'lodash'

const editCoord = reactive([-1, -1])
const editCoordProp = ref(null)
const editItem = ref({})

const maxColumnIndex = 2
const editColumnIndex = {
  1: 'name',
  2: 'address'
}

const options = [{
  value: 'Option1',
  label: 'Option1',
}, {
  value: 'Tom',
  label: 'Tom',
}, {
  value: 'Option2',
  label: 'Option2',
}, {
  value: 'Option3',
  label: 'Option3',
}, {
  value: 'Option4',
  label: 'Option4',
}, {
  value: 'Option5',
  label: 'Option5',
}]

onMounted(() => {
});

/**
 * 将表格列转换成编辑状态
 * @param rowIndex 行索引
 * @param columnIndex 列索引
 * @param cell 单元格元素
 */
const activateEdit = async(rowIndex, columnIndex, cell) => {
  const columnProp = editColumnIndex[columnIndex]
  if (columnProp) {
    // 执行编辑操作
    // 可以根据需要进行相应的逻辑处理
    // console.log(`将第 ${rowIndex} 行的 ${columnProp} 列转换为编辑状态`);
    editCoord[0] = rowIndex
    editCoord[1] = columnIndex
    editCoordProp.value = rowIndex + '_' + columnProp;
    await nextTick();
    const vm = getComponentInstance(cell);
    if (vm) {
      focusElement(vm)
    }
  } 
}

/**
 * 移动到下一个表单
 * 
 * @param direction 方向
 */
const activateEditNext = (direction) => {
  const rowIndex = editCoord[0]
  const columnIndex = editCoord[1]
  const ncc = nextCellCoord(direction)
  if (ncc[0] === rowIndex && ncc[1] === columnIndex) {
    return
  }
  const cell = getCellElement(ncc[0], ncc[1]);
  if (cell) {
    activateEdit(ncc[0], ncc[1], cell)
  }
}

/**
 * 使元素获取焦点
 * @param vm 元素
 */
 const focusElement = async(vm) => {
  if (vm) {
    // 延时 10 毫秒执行 nextElement.focus()
    await new Promise(resolve => setTimeout(resolve, 10));
    vm.focus();
  }
}

/**
 * 通过行索引和列索引获取单元格元素
 * @param rowIndex 行索引
 * @param columnIndex 列索引
 */
const getCellElement = (rowIndex, columnIndex) => {
  const currentVm = editItem.value
  if (!currentVm || rowIndex < 0 || columnIndex < 0) {
    return null;
  }
  const currentCell = currentVm.$el.closest('.el-table__cell');
  if (currentCell) {
    // 获取所在行元素
    const currentRow = currentCell.closest('.el-table__row');
    if (currentRow) {
      const row = Array.from(currentRow.parentNode.children)[rowIndex];
      if (!row) {
        return null;
      }
      // 使用 querySelectorAll 获取所有匹配的单元格元素
      const cells = row.querySelectorAll('.el-table__cell');
      return cells[columnIndex] || null;
    }
  }
  return null;
}

/**
 * 处理表格点击事件
 * @param event 点击事件对象
 */
const handleTableClick = (event) => {
  // 获取点击的单元格元素
  const cell = event.target.closest('.el-table__cell');
  if (cell) {
    // 获取所在行元素
    const row = cell.closest('.el-table__row');
    if (row) {
      // 计算行索引
      const rowIndex = Array.from(row.parentNode.children).indexOf(row);
      // 获取列索引
      const columnIndex = Array.from(cell.parentNode.children).indexOf(cell);
      // console.log(`点击的单元格位于第 ${rowIndex} 行，第 ${columnIndex} 列`);
      activateEdit(rowIndex, columnIndex, cell);
    }
  }
}

/**
 * 处理输入框失去焦点事件
 * @param event 失去焦点事件对象
 */
const handleInputBlur = () => {
  editCoord[0] = -1
  editCoord[1] = -1
  editCoordProp.value = null
}

// 定义处理键盘按键事件的方法
const allowedKeys = ['Enter', 'ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight']
const handleKeyDown = (event) => {
  if (!allowedKeys.includes(event.key)) {
    return
  }
  activateEditNext(getDirection(event.key))
}

const handleSelectChange = () => {
  activateEditNext('right')
}

const handleVisibleChange = (visible) => {
  if (!visible) {
    activateEditNext('right')
  }
}

/**
 * 通过元素查找组件实例
 * @param element 元素
 */
const getComponentInstance = (element) => {
  if (!editItem.value) {
    return null
  }
  if (!element) {
    return null
  }
  if (editItem.value.$el && element.contains(editItem.value.$el)) { 
    return editItem.value
  }
  return null
}

/**
 * 获取下一个表单元素
 * @param currentElement 当前表单元素
 * @param direction 方向['up', 'down', 'left', 'right']
 */
const nextCellCoord = (direction) => {
  const rowIndex = editCoord[0]
  const columnIndex = editCoord[1]
  if (-1 === rowIndex || -1 === columnIndex || !editItem.value) {
    return [rowIndex, columnIndex];
  }
  let nextRowIndex = rowIndex, nextColumnIndex = columnIndex;
  if (['left', 'right'].includes(direction)) {
    [nextRowIndex, nextColumnIndex] = moveColumnIndex(rowIndex, columnIndex, direction);
  } else if ('up' === direction) {
    nextRowIndex = rowIndex > 0 ? rowIndex - 1 : rowIndex;
  } else if ('down' === direction) {
    nextRowIndex = rowIndex < tableData.length - 1 ? rowIndex + 1 : rowIndex;
  } else {
    return [rowIndex, columnIndex];
  }
  return [nextRowIndex, nextColumnIndex];
}

const moveColumnIndex = (rowIndex, columnIndex, direction) => {
  let ri = rowIndex, ci = columnIndex;
  while(ri >= 0 && ri < tableData.length) {
    ci = direction === 'left'? ci - 1 : ci + 1;
    if (ci < 0) {
      ri = ri - 1;
      ci = maxColumnIndex;
    } else if (ci > maxColumnIndex) {
      ri = ri + 1;
      ci = 0;
    }
    if (editColumnIndex[ci]) {
      break;
    }
  }
  return [ri, ci]
}

/**
 * 根据按键事件获取方向
 * @param key 键盘事件
 */
 const getDirection = (key) => {
  if (key === 'ArrowUp') {
    return 'up'
  } else if (key === 'ArrowDown') {
    return 'down'
  } else if (key === 'ArrowLeft') {
    return 'left'
  } else if (key === 'ArrowRight') {
    return 'right'
  } else {
    return 'right'
  }
}
</script>

<style scoped>
</style>